﻿#include "pinyinresource.h"

#include <iostream>
#include <fstream>
#include <locale>
#include <codecvt>
#include <vector>
#include <stdio.h>

#ifdef _WIN32
# include <windows.h>
#else
# include "unicode.hpp"
#endif

//var
static std::wstring gResourceDir;

static std::map<std::wstring, std::wstring> gChineseMap;
static std::map<std::wstring, std::wstring> gPinyinTable;
static std::map<std::wstring, std::wstring> gMutilPinyinTable;

//fun
std::wstring& trim(std::wstring &s);
void split(std::wstring& s, std::wstring& delim,std::vector< std::wstring >* ret);
void replace(std::wstring &strBase, std::wstring strSrc, std::wstring strDes);
std::wstring toUpper(const std::wstring &data);

size_t UTF16toUTF8(const wchar_t *src, size_t srcLength, char *dst, size_t dstLength);
size_t UTF8toUTF16(const char *src, size_t srcLength, wchar_t *dst, size_t dstLength);
void copyFromUTF8(std::wstring &data, const char *s, size_t length);

PinyinResource::PinyinResource() {

}

PinyinResource::~PinyinResource() {

}

void PinyinResource::initPinyinResource(std::wstring resourceDir) {
    gResourceDir = resourceDir;
}

std::map<std::wstring, std::wstring>& PinyinResource::getResource(std::wstring file, std::map<std::wstring, std::wstring> &map) {
    if(gResourceDir.empty()) {
        printf("You must call PinyinResource::initPinyinResource set dict dir");
        return map;
    }

    std::string line;
    std::ifstream infile;

    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;

    infile.open(conv.to_bytes(file),std::ios::in);
    while(!infile.eof()){ // 若未到文件结束一直循环
        std::getline(infile, line, '\n');//读取一行，以换行符结束
        std::wstring wideLine;
        copyFromUTF8(wideLine,line.c_str(),line.length());
        wideLine = trim(wideLine);
        std::vector<std::wstring> ret;
        std::wstring delim = L"=";
        split(wideLine,delim,&ret);
        if(ret.size() >= 2) {
            map.insert(std::make_pair(ret[0],ret[1]));
        }
    }
    infile.close();
    return map;
}

std::map<std::wstring, std::wstring>& PinyinResource::getPinyinResource() {
    std::wstring file = L"/pinyin.dict";
    std::wstring path = gResourceDir + file;
    return getResource(path,gPinyinTable);
}

std::map<std::wstring, std::wstring>& PinyinResource::getMutilPinyinResource() {
    std::wstring file = L"/mutil_pinyin.dict";
    std::wstring path = gResourceDir + file;
    return getResource(path,gMutilPinyinTable);
}

std::map<std::wstring, std::wstring>& PinyinResource::getChineseResource() {
    std::wstring file = L"/chinese.dict";
    std::wstring path = gResourceDir + file;
    return getResource(path,gChineseMap);
}


std::wstring& trim(std::wstring &s) {
    if (s.empty()) {
        return s;
    }

    s.erase(0,s.find_first_not_of(L" "));
    s.erase(s.find_last_not_of(L" ") + 1);
    return s;
}

void split(std::wstring& s, std::wstring& delim, std::vector< std::wstring >* ret) {
    size_t last = 0;
    size_t index=s.find_first_of(delim,last);
    while (index!=std::wstring::npos) {
        ret->push_back(s.substr(last,index-last));
        last=index+1;
        index=s.find_first_of(delim,last);
    }
    if (index-last>0) {
        ret->push_back(s.substr(last,index-last));
    }
}

void replace(std::wstring &strBase, std::wstring strSrc, std::wstring strDes)
{
    std::wstring::size_type pos = 0;
    std::wstring::size_type srcLen = strSrc.size();
    std::wstring::size_type desLen = strDes.size();
    pos=strBase.find(strSrc, pos);
    while ((pos != std::wstring::npos))
    {
        strBase.replace(pos, srcLen, strDes);
        pos=strBase.find(strSrc, (pos+desLen));
    }
}

size_t UTF16toUTF8(const wchar_t *src, size_t srcLength, char *dst, size_t dstLength)
{
  size_t len = 0;

#ifdef _WIN32

  len = ::WideCharToMultiByte(CP_UTF8, 0, src, srcLength, dst, dstLength, NULL, NULL);

#else

  using namespace Unicode;

  const UTF16 *srcBegin = src;
  const UTF16 *srcEnd   = srcBegin + srcLength;

  UTF8 *dstBegin = reinterpret_cast<UTF8*>(dst);
  UTF8 *dstEnd   = dstBegin + dstLength;

  ConversionResult result = ConvertUTF16toUTF8(
    &srcBegin, srcEnd, &dstBegin, dstEnd, lenientConversion);

  if(result == conversionOK)
    len = dstBegin - reinterpret_cast<UTF8*>(dst);

#endif

  //if(len == 0)
  //  debug("String::UTF16toUTF8() - Unicode conversion error.");

  return len;
}

size_t UTF8toUTF16(const char *src, size_t srcLength, wchar_t *dst, size_t dstLength)
{
  size_t len = 0;

#ifdef _WIN32

  len = ::MultiByteToWideChar(CP_UTF8, 0, src, srcLength, dst, dstLength);

#else

  using namespace Unicode;

  const UTF8 *srcBegin = reinterpret_cast<const UTF8*>(src);
  const UTF8 *srcEnd   = srcBegin + srcLength;

  UTF16 *dstBegin = dst;
  UTF16 *dstEnd   = dstBegin + dstLength;

  ConversionResult result = ConvertUTF8toUTF16(
    &srcBegin, srcEnd, &dstBegin, dstEnd, lenientConversion);

  if(result == conversionOK)
    len = dstBegin - dst;

#endif

  //if(len == 0)
  //  debug("String::UTF8toUTF16() - Unicode conversion error.");

  return len;
}


void copyFromUTF8(std::wstring &data, const char *s, size_t length)
{
  data.resize(length);

  if(length > 0) {
    const size_t len = UTF8toUTF16(s, length, &data[0], data.size());
    data.resize(len);
  }
}


std::wstring toUpper(const std::wstring &data)
{
  std::wstring s;

  static int shift = 'A' - 'a';

  for(std::wstring::const_iterator it = data.begin(); it != data.end(); ++it) {
    if(*it >= 'a' && *it <= 'z')
      s.push_back(*it + shift);
    else
      s.push_back(*it);
  }

  return s;
}
